<?php

/*

Desktopd Colors
Copyright (C) 2015  Desktopd Developer(s)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

https://www.gnu.org/licenses/agpl.html

*/


namespace Desktopd\Colors;

use Desktopd\PlatformTools\Random;


class RandomWalk {
    const L_MAX = 100;
    const L_MIN = 0;
    
    const u_MAX = 220;//176
    const u_MIN = -134;//-84
    
    const v_MAX = 122;//108
    const v_MIN = -140;//-131
    
    protected $sRGB;
    
    protected $L_stddev;
    protected $u_stddev;
    protected $v_stddev;
    
    protected $Luv;
    
    protected function setCIELUV ($L, $u, $v) {
        $Luv = new CIELUV($L, $u, $v);
        $whitepoint = (new sRGB(1, 1, 1))->toXYZ();
        $XYZ = $Luv->toXYZ($whitepoint);
        $xyY = xyY::fromXYZ($XYZ);
        
        $this->sRGB = sRGB::fromXYZ($XYZ, true);
        
        $this->Luv = $Luv;
    }
    
    public function resetUniform () {
        while (true) {
            try {
                $this->setCIELUV(
                    Random::float(self::L_MIN, self::L_MAX),
                    Random::float(self::u_MIN, self::u_MAX),
                    Random::float(self::v_MIN, self::v_MAX)
                );
                break;
            } catch (\Exception $e) {
                continue;
            }
        }
        
        return true;
    }
    
    public function __construct ($step = 16) {
        $this->resetUniform();
        
        $this->L_stddev = Random::exponential(1 / $step);
        $this->u_stddev = Random::exponential(1 / $step);
        $this->v_stddev = Random::exponential(1 / $step);
    }
    
    public function move () {
        while (true) {
            try {
                $L = $this->Luv->getL() + Random::normal(0, $this->L_stddev);
                $u = $this->Luv->get_u() + Random::normal(0, $this->u_stddev);
                $v = $this->Luv->get_v() + Random::normal(0, $this->v_stddev);
                $this->setCIELUV($L, $u, $v);
                break;
            } catch (\Exception $e) {
                continue;
            }
        }
        
        return true;
    }
    
    public function __invoke( ) {
        return $this->move();
    }
    
    public function __toString () {
        return sprintf('%s: %s with stddev (%.3F, %.3F, %.3F); %s',
            __CLASS__,
            $this->Luv,
            $this->L_stddev,
            $this->u_stddev,
            $this->v_stddev,
            $this->sRGB
        );
    }
    
    public function sRGB () {
        return $this->sRGB;
    }
    
    public function getCIELUV () {
        return $this->Luv;
    }
}


// vim: ts=4 et ai

